<?php
/*
 * Copyright (c) 2013 Eugene Kuzmenko
 *
 * Permission  is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in  the Software without restriction, including without limitation the rights
 * to  use,  copy,  modify,  merge, publish, distribute, sublicense, and/or sell
 * copies  of  the  Software,  and  to  permit  persons  to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The  above  copyright  notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE  IS  PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED,  INCLUDING  BUT  NOT  LIMITED  TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS  FOR  A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS  OR  COPYRIGHT  HOLDERS  BE  LIABLE  FOR  ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 * For more information, see <http://www.aljey.com>.
 */

namespace Al\Admin\Controller;

use Al\Core\Lib\Controller,
    Al\Core\Lib\Service;

/**
 * @author Eugene Kuzmenko <mail@aljey.com>
 */
class DBController extends Controller {

  /**
   * Renders the admin page.
   */
  public function mainAction() {
    $info = $this->getDBInfo();
    $config = Service::get('config');
    $em = Service::get('em');
    try { $meta = $em->getDBMeta(); }
    catch (\Exception $e) { $meta = array(); }
    $info['plugins'] = array_keys($config['plugin_list']);
    $info['entities'] = array_map(function ($entity) use (&$em) {
      return $em->entityShortClass($entity);
    }, array_keys($config['mapping']));
    $info['tables'] = array_map(function ($item) {
      return $item->name;
    }, $meta);
    return $this->render($this->getConfig('admin'), $info);
  }

  /**
   * Creates the database.
   */
  public function createDatabaseAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('createDatabase'),
    ) + $this->getDBInfo()), 'json');
  }

  /**
   * Removes the database.
   */
  public function removeDatabaseAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('dropDatabase'),
    ) + $this->getDBInfo()), 'json');
  }

  /**
   * Creates the schema.
   */
  public function createSchemaAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('createSchema'),
    )), 'json');
  }

  /**
   * Updates the schema.
   */
  public function updateSchemaAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('updateSchema'),
    )), 'json');
  }

  /**
   * Removes the schema.
   */
  public function removeSchemaAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('dropSchema'),
    )), 'json');
  }

  /**
   * Generates entities.
   */
  public function generateEntitiesAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('generateEntities'),
    )), 'json');
  }

  /**
   * Imports database mapping.
   */
  public function importMappingAction() {
    $post = Service::get('http.post');
    $params = array($post['plugin']);
    if ($tables = $post['tables']) $params[] = $tables;
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('importMapping', $params),
    )), 'json');
  }

  /**
   * Clears Doctrine cache.
   */
  public function clearDBCacheAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('clearCache'),
    )), 'json');
  }

  /**
   * Loads data fixture from all plugins.
   */
  public function loadFixturesAction() {
    return $this->renderText(json_encode(array(
      'message' => $this->updateDB('loadFixtures'),
    )), 'json');
  }

  /**
   * Generates CRUD controllers.
   */
  public function generateCrudAction() {
    $entity = Service::get('http.post.entity');
    $ns = explode(':', $entity);
    $message = 'Success';
    try {
      $path = call_user_func(array(Service::get('em'), 'generateCrud'), $ns[0],
        $entity);
    } catch (\Exception $e) {
      $message = $e->getMessage();
      $path = '#';
    }
    return $this->renderText(json_encode(array(
      'message' => $message,
      'path' => $path,
    )), 'json');
  }

  /**
   * Invokes the specified method on the entity manager.
   *
   * @param string $method
   * @param array $params
   * @return string
   */
  private function updateDB($method, $params = array()) {
    $message = 'Success';
    try { call_user_func_array(array(Service::get('em'), $method), $params); }
    catch (\Exception $e) { $message = $e->getMessage(); }
    return $message;
  }

  /**
   * Retrieves information about the current db connection.
   *
   * @return array
   */
  private function getDBInfo() {
    $connected = 'Connected successfully';
    $conn = Service::get('em')->getConnection();
    $database = $conn->getDatabase();
    $db_to_create = false;
    $db = $database ? "Database \"$database\" exists." :
      'No database is configured.';
    $yaml = Service::get('yaml');
    $config = Service::get('config');
    $conn->close();
    try { $conn->connect(); }
    catch (\Exception $e) {
      $connected = $e->getMessage();
      if ($database) {
        $db = "Database \"$database\" doesn't exist.";
        $db_to_create = true;
      } else {
        $db = 'No database is configured.';
      }
    }
    return array(
      'connected' => $connected,
      'db_config' => $yaml->dump(array(
        'database' => $config['params']['database'],
      )),
      'mapping' => $yaml->dump(array(
        'mapping' => $config['mapping'],
      )),
      'db' => $db,
      'db_to_create' => $db_to_create,
    );
  }

}